/****************************************************************************\ * * hpidd.c * * This module determines the HP laptop product IDs. * * 00/06/30 lnc - V1.12, updated for Jaws. * 00/02/17 bw - V1.11, updated for Oddjob 2, Sterling. * 98/06/09 lnc - V1.10, updated for Galileo 2, Voyager 2, Oddjob. * 98/06/05 lnc - V1.09, updated for Apollo 2. * 98/06/02 lnc - V1.08, removed GetDMIdata() and SMI function * method from iGet_Prod_ID(); reorganized routine order. * 98/05/20 lnc - V1.07, modified HP_ID_Table[] and vCheck_HP_ID() * to distinguish Tillamook from Deschutes and OB3100 * from OB2100 for use of DMI tables; vCheck_HP_ID() now * gets BIOS ID and model name to use with added * routine vTune_HP_ID(). * 98/05/01 lnc - V1.06, renamed GetProdID to iGet_Prod_ID(). * 98/03/01 lnc - V1.05, added modifications to GetProdID() to * directly access DMI structures from the SMBIOS * structure table; modified renamed HP_ID_Table to * set appropriate index for product ID returned from * GetProdID() through direct access to DMI structures, * SMBIOS function access to DMI structures, or * INT 15h, function 4DD4h. * 98/02/18 lnc - V1.04, modified key IDs of HpIDTable, and * iDo_Int15() for new version of INT 15 - qCX.MY.ZZ, * BIOS version 37a. * 98/02/11 lnc - V1.03, modified key IDs of HpIDTable, and * iDo_Int15() for new version of INT 15 - q.CX.MY.ZZ, * BIOS version 35a. * 98/01/19 lnc - V1.02, modified key IDs of HpIDTable, debug for * iDo_Int15(). * 97/12/10 lnc - V1.01, modified for Medium model, added new * catagory to LookUp structure for a this test program. * 97/12/08 bw - V1.00, created. * \****************************************************************************/ #include <stdio.h> #include <string.h> #include "model.h" #define MAXBUFSIZE 8192 #define BID_BA 0x4241 #define BID_CB 0x4342 #define BID_CC 0x4343 #define BID_CD 0x4344 #define BID_CE 0x4345 #define BID_CF 0x4346 #define BID_CG 0x4347 #define BID_CH 0x4348 #define BID_CI 0x4349 #define BID_CJ 0x434A #define BID_CK 0x434B #define BID_CL 0x434C #define BID_C0 0x4330 #define BID_EA 0x4541 #define BID_FA 0x4641 typedef struct { unsigned inSig; int key; } LookUp; typedef unsigned char BYTE; typedef unsigned short WORD; int iGet_Prod_ID (void); static BYTE far *bfpFind_Dmi_Table(void); static int iGetPlatformId(char far *cpPtr); static void vCheck_HP_ID(BYTE far *fpntr); static char far *cfpGet_String(int n, BYTE far *fpntr); static void vTune_HP_ID(void); static BYTE far *bfpGet_Next_Structure(BYTE far *s); static unsigned uDo_Int15 (void); static LookUp HP_ID_Table[] = { {0x0301, OB4000}, // 1 Pegasus {0x0401, OB5000}, // 2 Tristar {0x0402, OB5500}, // 3 Quadstar {0x0403, OB5700}, // 4 AA, Polaris {0x0404, OB2000}, // 5 AA, Reno {0x0501, OB800O}, // 6 Orion {0x0502, OB800M}, // 7 AB, Mercury, MMX {0x0601, OB3000}, // 8 CA, Magellan {BID_BA, OBSOJOURN}, // 9 BA, Sputnik {BID_CB, OB7100T}, // 10 CB, Galileo 1, Tillamook {BID_CC, OB7100D}, // 11 CC, Galileo 1, Deschutes {BID_CH, OB7150}, // 12 CH, Galileo 2, Deschutes, 300 Mhz {BID_CD, OB4100T}, // 13 CD, Voyager 1, Tillamook {BID_CE, OB4100D}, // 14 CE, Voyager 1, Deschutes {BID_CI, OB4150A}, // 15 CI, Voyager 2, Deschutes, 300 Mhz {BID_CF, OB3100}, // 16 CF, Apollo 1, Tillamook, 266 Mhz {BID_C0, OB2100T}, // 17 CF, Apollo 1, Tillamook, 233 Mhz {BID_CG, OB2100D}, // 18 CG, Apollo 2, Deschutes, 266 Mhz {BID_CJ, OB900A}, // 19 CJ, Oddjob, Deschutes, 266 Mhz {BID_CK, OB4150B}, // 20 CK, Voyager 3.9, 4, 4.2 {BID_CL, OB900B}, // 21 CL, Oddjob 2, 2.5, 2.7 {BID_EA, OB6000}, // 22 EA, Sterling {BID_FA, OB500}, // 23 FA, Jaws {0, 0} // Marks end of table }; static char HP_Str[] = "HP OmniBook PC"; #define HP_STR_BSZ (sizeof HP_Str) - 3 static char Model_Bf[16] = ""; static unsigned uBIOS_Sig = 0; static unsigned uProdID = 0; static unsigned uOmniBook = 0; /****************************************************************************\ * iGet_Prod_ID * * Identify the computer, first trying the DMI tables and if that * fails then trying INT 15 function 4DD4. * * Output: * return - -1, unknown * -2, Vectra * OB4000, OB 4000 * OB5000, OB 5000 * OB5500, Quadstar * OB5700, Polaris * OB2000, Reno * OB800O, Orion0 * OB800M, Mercury, MMX * OB3000, Magellan * OBSOJOURN, Sputnik * OB7100T, Galileo 1, Tillamook * OB7100D, Galileo 1, Deschutes * OB7150, Galileo 2, Deschutes, 300 Mhz * OB4100T, Voyager 1, Tillamook * OB4100D, Voyager 1, Deschutes * OB4150A, Voyager 2, Deschutes, 300 Mhz * OB4150B, Voyager 3.9, 4, 4.2 * OB3100, Apollo 1, 266 Mhz * OB2100T, Apollo 1, 233 Mhz * OB2100D, Apollo 2, Deschutes, 266 Mhz * OB900A, Oddjob, Deschutes, 266 Mhz * OB900B, Oddjob 2 * OB6000 Sterling * OB500 Jaws. \****************************************************************************/ int iGet_Prod_ID(void) { BYTE far *fpntr; unsigned int i; uBIOS_Sig = 0; uProdID = 0; uOmniBook = 0; // first try accessing DMI tables directly if ((fpntr = bfpFind_Dmi_Table()) != NULL) { do { vCheck_HP_ID(fpntr); if (uOmniBook && uBIOS_Sig) { vTune_HP_ID(); // tune for crummy DMI design for (i = 0; HP_ID_Table[i].inSig != 0; i++) if (HP_ID_Table[i].inSig == uBIOS_Sig) return HP_ID_Table[i].key; // OK break; // bad product ID, NOT found in table } } while ((fpntr = bfpGet_Next_Structure(fpntr)) != 0); } // DMI did not work, use INT 15h , function 4DD4h if ((uProdID = uDo_Int15()) < 0) return (int) uBIOS_Sig; // NOT HP OmniBook for (i = 0; HP_ID_Table[i].inSig != 0; i++) if (HP_ID_Table[i].inSig == uBIOS_Sig) return HP_ID_Table[i].key; // OK return return -1; // NOT found in table } /****************************************************************************\ * bfpFind_Dmi_Table * * This function searches BIOS segment F000h for the signature "_DMI_" * and returns a pointer to the SMBIOS structure table. * * Output: * return - NULL, "_DMI_" signature notfound * pointer to SMBIOS structure table. \****************************************************************************/ static BYTE far * bfpFind_Dmi_Table(void) { BYTE far *pDmiTable; _asm { push es push bx push cx mov ax, 0xf000 ; start at beginning of F000h segment mov es, ax xor bx, bx Loop1: ; look for "_DMI_" signature cmp WORD PTR es:[bx], 'D_' ; "_D" jne NotYet cmp WORD PTR es:[bx + 2], 'IM' ; "MI" jne NotYet cmp BYTE PTR es:[bx + 4], '_' ; "_" je FoundDmi NotYet: add bx, 0x10 ; next paragraph still in segment jnc Loop1 ; yes xor bx, bx ; no, signature not found, xor cx, cx ; return NULL pointer jmp Done FoundDmi: ; found it, get 32-bit real mode physical starting address of ;read-only SMBIOS structure table mov cx, WORD PTR es:[bx + 9] ; get segment shl cx, 1 shl cx, 1 shl cx, 1 shl cx, 1 mov bx, WORD PTR es:[bx + 8] ; get offset and bx, 0xff Done: mov WORD PTR pDmiTable, bx ; save offset mov WORD PTR pDmiTable[2], cx ; save segment pop cx pop bx pop es } return pDmiTable; } /****************************************************************************\ * iGetPlatformId * * Input: * cpPtr - pointer to a structure in the SMBIOS * structure table. * * Output: * return - -1, not an Omnibook * xy, 2-character platform ID (iOmniBook == 1). \****************************************************************************/ static int iGetPlatformId(char far *cpPtr) { int iRtn; while (*(cpPtr++) != '.') ; if (*cpPtr == 'M') { uOmniBook = 1; iRtn = ((int) *(cpPtr - 3) << 8); iRtn |= (int) *(cpPtr - 2); return iRtn; } return -1; } /****************************************************************************\ * vCheck_HP_ID * * This routine checks the SMBIOS structure table for structures of * type 1h and 80h for Product Name and Notebook ID, respectively. * * Input: * fpntr - pointer to a structure in the SMBIOS * structure table. * * Output: * sets uBIOS_Sig to BIOS ID if structure type 0h is found, * sets uOmniBook to 1 if structure type 1h is found, * sets uProdID to product ID if structure 80h is found: * 7, Galileo * 8, Voyager * 9, Apollo. \****************************************************************************/ static void vCheck_HP_ID(BYTE far *fpntr) { char far *fstr; int iTmp; switch (*fpntr) { case 0x00: // Type 0h: BIOS Information // get BIOS version iTmp = iGetPlatformId(cfpGet_String(0x5, fpntr)); if (iTmp != -1) uBIOS_Sig = (unsigned) iTmp; else uBIOS_Sig = 0; return; case 0x01: // Type 1h: System Information // check product name if (_fstrcmp(cfpGet_String(0x5, fpntr), HP_Str) == 0) uOmniBook = 1; // Product Name checks out // get model name if (_fstrncmp((fstr = cfpGet_String(0x6, fpntr)), HP_Str, HP_STR_BSZ) == 0) _fstrcpy(Model_Bf, fstr + HP_STR_BSZ); return; case 0x80: // Type 80h: HP ID // get notebook ID uProdID = *(fpntr + 6); return; } } /****************************************************************************\ * cfpGet_String * * This routine finds a string in the string area of an SMBIOS structure. * * Input: * n - offset of string type, determining string * number * fpntr - pointer to a structure in the SMBIOS * structure table. * * Output: * returns - NULL, length byte is zero * pointer to a string in a structure of * finite length; string may be a NULL string. \****************************************************************************/ static char far * cfpGet_String(int n, BYTE far *fpntr) { unsigned i, j; BYTE far *p; if ((j = *(fpntr + 1)) == 0) return NULL; // length of formatted area is zero p = fpntr + j; // point to start of string section j = *(fpntr + n); // get string number for (i = 1; i < j; i++) while (*p++) ; // move to start of appropriate string return (char far *) p; } /****************************************************************************\ * vTune_HP_ID * * This routine splits the 'CF' from the OB2100 & 3100 into 2 IDs * \****************************************************************************/ static void vTune_HP_ID(void) { switch (uBIOS_Sig) { case BID_CF: uBIOS_Sig = (Model_Bf[0] == '2') ? BID_C0 : BID_CF; return; } } /****************************************************************************\ * bfpGet_Next_Structure * * This routine searches to the end of a structure for the start of * the next structure in the SMBIOS structure table. * * Input: * s - pointer to a structure in the SMBIOS * structure table. * * Output: * returns - NULL, length byte is zero * pointer to next structure. \****************************************************************************/ static BYTE far * bfpGet_Next_Structure(BYTE far *s) { unsigned len; // get length of formatted area if ((len = *(s + 1)) == 0) return NULL; // length of formatted area is zero // point to string area and move past end for (s += len; *s != '\0' || *(s + 1) != '\0'; s++) ; s += 2; // point at next structure return s; } /****************************************************************************\ * uDo_Int15 * * Do INT 15 function 4DD4h. * * Output: * return - -1, Not HP OmniBook, int 15 funct 4DD4 * not supported * -2, Vectra (int 15 funct 4DD4 returned * HP div ID != MCD) * nn, For old OB, nn = chip set + model; * for newer OB, nn = 2 letter platform * identifier. * * Note - OB800, OB3000 and probably older versions of the Omnibook * use the old version of INT 15h. \****************************************************************************/ static unsigned uDo_Int15(void) { unsigned axreg; _asm { push es push di mov ax, 0x4DD4 int 15h cmp bx, 'HP' // BX == 0x4850 ? je OldOB // Yes, old version of INT 15h cmp bx, 'hp' // BX == 0x6870 ? jne NotOB // NO, error, not a OmniBook // ES:DI -> <blank>AA.UX.YY, qAA.UX.YY, cAA.UX.YY, bAA.UX.YY, // or AA.UX.YY mov al, es:[di] // YES, check first character for // ' ', 'q', 'c', or 'b' cmp al, ' ' je Prfx cmp al, 'q' je Prfx cmp al, 'c' je Prfx cmp al, 'b' jne NoPrfx Prfx: inc di NoPrfx: mov ax, es:[di] // get AA field xchg ah, al cmp byte ptr es:[di + 3], 'M' // U field == M for MCD ? je Exit // YES, MCD mov ax, -2 // NO, must be Vectra jmp Exit OldOB: mov ax, cx // CH = chip set, CL = model jmp Exit // Magellan, Mercury, Orion, etc. NotOB: mov ax, -1 // not Hewlett-Packard product Exit: pop di pop es mov axreg, ax } return axreg; }